/*
 * @brief C++11 变长模板测试
 * @auther aolei1024@gmail.com
 * @date 2020-05-28
 */
#ifndef _TEMPLATE_TEST_H_
#define _TEMPLATE_TEST_H_

#include <string>
#include <memory>
#include <iostream>
#include <type_traits>
#include <tuple>
#include "demo.h"
struct BaseSystem
{
    virtual std::string Show() = 0;
};

struct MoveSystem :public BaseSystem
{
    std::string Show()
    {
        return "MoveSystem";
    }
};
struct RoleSystem :public BaseSystem
{
  std::string Show()
    {
        return "RoleSystem";
    }
};

#define CREATE_SYSTEM(T) \
    private:            \
    T T##manage;        \
    public:             \
    T& Get##T()         \
    {                   \
        return T##manage;\
    }
/*
template<typename... Systems>
class SystemMgr
{
    public:
        template<typename T>
        std::shared_ptr<BaseSystem> Get()
        {
            return list[T::index];
        }
    private:
        const static int size = sizeof...(Systems);
        std::shared_ptr<BaseSystem> list[size];
};
*/
struct SystemShow
{
    template<typename Func>
    SystemShow(Func&& func,std::string name,int a)
    {
        std::cout<<name<<"\tSystemShow(Func&& func,std::string name,int a)"<<std::endl;
    }
    template<typename Func>
    SystemShow(Func&& func,std::string name)
    {
        std::cout<<name<<"\tSystemShow(Func&& func,std::string name)"<<std::endl;
    }
};

/*
template<int index, class FuntionType>
struct ArgTypeAt;

template<class ResultType, class FirstArgType, class... ArgsType>
struct ArgTypeAt<0, ResultType(FirstArgType, ArgsType...)>
{
    using type = FirstArgType;
};

template<int index, class ResultType, class FirstArgType, class... ArgsType>
struct ArgTypeAt<index, ResultType(FirstArgType, ArgsType...)>
{
    using type = typename ArgTypeAt<index - 1, ResultType(ArgsType...)>::type;
};
*/
class FuncStr
{
    public:
    static void Func(int a,std::string b,float c)
    {

    }
};

class SystemTest
{
    public:
        template<typename... Systems>
        void Do();
        template<typename System>
        void Doone();
        template<typename... Args>
        void Join(Args&&... args)
        {
            auto a = SystemShow(std::forward<Args>(args)...);
        }
        template <typename T>
        void FuncTest(T func)
        {
            /*
            using FuncT = ArgType<decltype(func)>;
            std::cout<<"参数数量："<<FuncT::paramCount<<std::endl;
            typename FuncT::types tup = std::make_tuple(1,"hello world",1.0f);

            std::cout << "ID: 0, "
                << "GPA: " << std::get<0>(tup) << ", "
                << "grade: " << std::get<1>(tup) << ", "
                << "name: " << std::get<2>(tup) << '\n';
            typename FuncT::template paramType<0> one = 1;
            std::cout<<one<<std::endl;
            */
        }
        void Show()
        {
            Do<MoveSystem,RoleSystem>();
            MoveSystem a;
            Join(std::forward<MoveSystem>(a),"three args",1);
            Join( std::forward<MoveSystem>(a),"two args");
            FuncTest(&FuncStr::Func);
            FuncTest([](int a ,std::string b,float c,int d,float e){

            });

            MyClass one;
            one.Run();
        }
};

#include "template_test.inl"

#endif //_TEMPLATE_TEST_H_
